package com.ruoyi.project.system.function.service.impl;

import com.ruoyi.common.utils.security.ShiroUtils;
import com.ruoyi.framework.interceptor.SealInterceptor;
import com.ruoyi.framework.web.exception.DataException;
import com.ruoyi.framework.web.exception.FarmersDoNotExistException;
import com.ruoyi.framework.web.exception.YearDataAlreadyExistsException;
import com.ruoyi.project.system.base_family_info.domain.BaseFamilyInfo;
import com.ruoyi.project.system.base_family_info.mapper.BaseFamilyInfoMapper;
import com.ruoyi.project.system.dict.utils.DictUtils;
import com.ruoyi.project.system.function.bean.CategoryMap;
import com.ruoyi.project.system.function.domain.*;
import com.ruoyi.project.system.function.mapper.FunctionMapper;
import com.ruoyi.project.system.function.service.FunctionService;
import com.ruoyi.project.system.info.mapper.BaseFamilyInfoManagementMapper;
import com.ruoyi.project.system.user.domain.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
*
*
* @Author: 郑吉志
*
* @Create: 23.2.22
**/
@Slf4j
@Service
public class FunctionServiceImpl implements FunctionService {
    @Autowired
    private FunctionMapper functionMapper;
    @Autowired
    private BaseFamilyInfoMapper baseFamilyInfoMapper;
    @Autowired
    private BaseFamilyInfoManagementMapper baseFamilyInfoManagementMapper;
//    //list总数据
//    List<Map<Integer, String>> list;
//
//    //合并单元格的范围
//    List<int[]> mergerList=new ArrayList<>();
//    //组合合并单元格
//    Map<String,int[]> mergerMap=new HashMap<>();
//
//    //二级菜单对应一级菜单
//    Map<String,String> firstToSecond=new HashMap<>();
//
//    //三级菜单对应二级菜单
//    Map<String,String> secondToThird=new HashMap<>();
//
//    //三级菜单对应数据
//
//
//
//    //一级菜单
//    Map<Integer,String> firstCategory;
//    //二级菜单
//    Map<Integer,String> secondCategory;
//    //三级菜单
//    Map<Integer,String> thirdCategory;

    @Override
    public Integer selectStateByYear(Integer year) {
        return functionMapper.selectStateByYear(year);
    }

    @Override
    public void updateOverviewDB(OverviewDB overviewDB) {
        functionMapper.updateOverviewDB(overviewDB);
    }

    @Override
    public void sealByYear(Integer flag, Integer year) {
        functionMapper.sealByYear(flag,year);
    }

    @Override
    public void dataProcess(List<int[]> mergeList,List<Map<Integer, String>> list) {//List<Map<Integer, String>> list表示第一行第一个位置是什么
        log.info("这是dataProcess方法");
        log.info(list.toString());
        //list总数据
        //合并单元格的范围
        //组合合并单元格
        Map<String,int[]> mergerMap=new HashMap<>();

        //二级菜单对应一级
        // 菜单
        Map<String,String> firstToSecond=new HashMap<>();

        //三级菜单对应二级菜单
        Map<String,String> secondToThird=new HashMap<>();

        //一级菜单，key为位置，value为对应的数据
        Map<Integer,String> firstCategory=new HashMap<>();
        //二级菜单
        Map<Integer,String> secondCategory=new HashMap<>();
        //三级菜单
        Map<Integer,String> thirdCategory=new HashMap<>();

        //list表示整个表的数据
        //map只能存一行数据，想要存多行数据必须要用一个list集合将其存入
        List<Map<String, String>> thirdToData = new ArrayList<>();
        try {
            firstCategory = list.get(0);//list.get(0)为一个Map<Integer, String>，表示将得到的数据传给第一行map
            secondCategory = list.get(1);
            thirdCategory = list.get(2);

            //组合mergeMap-合并单元格
            for (int[] its : mergeList) {
                //its存四个数据，第一行，第一列，最后一行，最后一列
                int firstRow = its[0];
                int firstColum = its[1];
                if (firstRow == 0||firstRow>=list.size()||firstColum>=list.get(0).size())  //将第一行的数据踢掉
                    continue;

                Object s = list.get(firstRow - 1).get(firstColum);

                if (s!=null)
                    mergerMap.put(s.toString(), its);
            }

            //二级对应一级
            //entrySet()方法获取firstCategory中所有键值对组成的Set集合
            for (Map.Entry entry : firstCategory.entrySet()) {
                if (entry.getValue() == null || entry.getKey() == null)
                    continue;
                String name = entry.getValue().toString();
                //如果mergerMap中已经存储了一个名为name的单元格，那么就说明当前处理的这个单元格需要和已经存储的单元格进行合并，对其数据进行整合。
                if (mergerMap.containsKey(name)) {
                    //把合并后的单元格位置写出
                    int firstColum = mergerMap.get(name)[1];

                    int lastColum = mergerMap.get(name)[3];

                    for (int i = firstColum; i <= lastColum; i++) {
                        //如果在第一级收入中，第二级收入对应的列存在，把第二级收入对应的此列加入到一级收入对应的二级收入中
                        //不存在存在这一列，但是为空的情况
                        //则该条件多余，因为给定范围，并且该列不可能为空则一定对应
                        if (secondCategory.containsKey(i)) {
                            firstToSecond.put(secondCategory.get(i), name);
                        }
                    }
                }
            }
            //三级对应二级
            for (Map.Entry entry : secondCategory.entrySet()) {
                if (entry.getValue() == null || entry.getKey() == null)
                    continue;
                String name = entry.getValue().toString();
                if (mergerMap.containsKey(name)) {
                    int firstColum = mergerMap.get(name)[1];
                    int lastColum = mergerMap.get(name)[3];
                    for (int i = firstColum; i <= lastColum; i++) {
                        //判断二级收入的列对应的三级收入的列是否为空
                        //当需要删除这一个品种时，如果存在整个列，但是没有数据，就不需要添加到连表里
                        if (thirdCategory.get(i) != null)
                            secondToThird.put(thirdCategory.get(i), name);
                    }
                }
            }
            //三级对应数据
            thirdToData = new ArrayList<>();
            for (int i = 3; i < list.size(); i++) {  //list.get(3)为一个Map<Integer, String>，表示第四行的数据
                Map<Integer, String> map = list.get(i);
                Map<String, String> tmp = new HashMap<>();
                for (Map.Entry entry : map.entrySet()) { //便利第四行位置的集合
                    if (entry.getKey() == null || entry.getValue() == null)
                        continue;
                    String key = thirdCategory.get(entry.getKey()); //取第四行各个数据列的位置，得到这一列在的位置对应的名称
                    tmp.put(key, entry.getValue().toString()); //将名称与第四列所对应的值作为键值对
                }
                thirdToData.add(tmp);//将其加入到第三级数据中
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new DataException("数据有误，请检查");
        }
        compose(thirdToData,mergerMap,secondCategory,secondToThird,firstToSecond);
    }
    @Override
    public void add(int year,String fid) {
        //判断某一年这一户的信息是否存在，如果存在则跳过
        if (selectOverviewDB(fid,year)!=null)
            return;
        //新建一个年份表单记录一级收入
        OverviewDB overviewDB=new OverviewDB();
        //设置表单中各个数据
        overviewDB.setFid(fid);
        overviewDB.setReportYear(year);
        overviewDB.setState(0);
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
        Date date=new Date();
        overviewDB.setOpTime(sdf.format(date));

        //管理员账号
        User currentUser = ShiroUtils.getSysUser();
        // 获取当前的用户名称
        overviewDB.setUserId(currentUser.getUserId());
        saveOverviewDB(overviewDB);
    }

    /**
     * @Description: 组合对象
     * @Author: 郑吉志
    */
    public void compose(List<Map<String,String>> thirdToData, Map<String, int[]> mergerMap, Map<Integer, String> secondCategory, Map<String, String> secondToThird, Map<String, String> firstToSecond){

        //组合对象分多种情况:一对一、一对二、没有二级收入类别但有一级收入类别、没有一级收入类别和二级收入类别、其他项   ?一对三的情况没有吗
    
        //一对一、一对二的情况比较容易解决

        //没有二级收入类别 的 我们通过建立单独的map来存放其对应的value，我们将这类对象的二级收入类别赋值为value，将三级收入类别赋值为-1

        //没有一级收入类别和二级收入类别 的  这类对象不需要插入detail表，也就不需要建立对象，这类数据统一保存在overview对象中

        //其他项 我们新建一个 other map key=其他项的firstColum，value=二级收入类别  根据  thirdCategory-三级收入类别，key=firstColum value=二级收入类别  这样的两个map来进行映射

        //这个for循环只存放 一对一、一对二、没有二级收入类别的情况
        for (int i=0;i<=thirdToData.size();i++) {

            Map<String,String> map =thirdToData.get(i);
            int row=i+5;
            //使用Set避免重复填入
            //它可以存储字符串类型的元素且不允许重复。
            Set<String> set=new HashSet<>();
            List<DetailDB> detailDBList =new ArrayList<>();
            //先判断这一户是否存在
            //在判断输入的数据是否能对应数据库里一户的信息
//            if (selectName(map.get("户主姓名"))==null||selectName(map.get("户主姓名")).equals(""))
//                throw new DataException("农户  "+map.get("户主姓名")+"  不存在");
//            if (functionMapper.getFid(map.get("户主姓名"),Integer.parseInt(map.get("人口数")),Double.parseDouble(map.get("耕种面积")))==null)
//                throw new DataException("数据异常");
              if (selectHuZhu(map.get("户编号"))==null)
                  throw new DataException("第"+row+"行对应的户编号不存在");
            BaseFamilyInfo HuZhu=selectHuZhu(map.get("户编号"));
            String fid = map.get("户编号");
            String area=map.get("实际耕种");
            String twoArea=map.get("二轮（确权）面积");
            String otherArea=map.get("其他面积");
            if(area==""||area==null){
                area= String.valueOf(HuZhu.getArea());
            }
            if(twoArea==""||twoArea==null){
                twoArea= String.valueOf(HuZhu.getTwoArea());
            }
            if(otherArea==""||otherArea==null){
                otherArea= String.valueOf(HuZhu.getOtherArea());
            }
            BigDecimal area1= BigDecimal.valueOf(Double.parseDouble(area));
            BigDecimal twoArea1= BigDecimal.valueOf(Double.parseDouble(twoArea));
            BigDecimal otherArea1= BigDecimal.valueOf(Double.parseDouble(otherArea));
            baseFamilyInfoMapper.updateSomeBaseFamilyInfoByEdit(fid,area1,twoArea1,otherArea1);
            int i1 = mergerMap.get("年份")[1];
            String year=secondCategory.get(i1);

            //总之，就是如果没有这个户的数据，且数据库暂无信息则为其id设置为1，如果数据库有信息但无这一户，则获取最后一行id加一作为这一户的新id
            //如果有这一户的id，则直接取出这一户的id


            //判断一级表中是否有最后一条数据，如果有则返回值，如果没有则返回-1
            int tmp=getLastId()==null?-1:getLastId();
            int id;
            //如果没有年与户对应的这条消息，则为其找到最后一个id加一作为最新id
            if (functionMapper.selectOverviewDB(fid, Integer.parseInt(year))==null)
                id=tmp+1;
            //如果找到了消息，表明这条数据已经添加，找到这个数据的id
            else {
                OverviewDB db=functionMapper.selectOverviewDB(fid, Integer.parseInt(year));
                id=db.getId();
            }



     //一级收入对应的，生产经营，财产性，工资性，转移性收入
            double produceAmount=0;
            double propertyAmount=0;
            double salaryAmount=0;
            double transferAmount=0;
    //一个map表示一行数据，键为第三级收入名称，值为量
            for (Map.Entry entry : map.entrySet()) {
                if (entry.getValue()==null||entry.getKey()==null)
                    continue;
                //数据项-三级菜单
                //三级菜单项的统称
                String name=prefixStr(entry.getKey().toString());
                //三级菜单对应的项的详细称呼
                String allName = entry.getKey().toString();

                if(!allName.contains("金额")&&!allName.contains("产销"))
                    name=allName;

                //重复数据不填入
                //第一次执行无数据，不可能跳过
                if (set.contains(name))
                    continue;
                //根据三级菜单找到二级菜单和一级菜单
                String second=secondToThird.get(allName);

                String first=firstToSecond.get(second);
                //建立的一个字典对应级别表
                DetailDB info=new DetailDB();

                //对于没有二级菜单的数据，由于字典设计的这些菜单放到了二级字典，所以这里也是只给二级值，三级值默认给0
                //CategoryMap.map左边是收入表对应的各级收入名称，右边是对应的字典
                //这种情况是三级收入无对应的二级收入，但是字典记录了他，可以找到对应关系的情况
                if ((Objects.equals(second, "") || second == null) && CategoryMap.map.containsKey(allName)){
                    info.setIncomeDataId(id);
                    info.setFirstCategory(4);
                    //将其在字典类型对应的字典标签所属的数字表示出来，这个收入对应的一级收入的字典等于三级收入对应二级收入的字典
                    info.setSecondaryCategory(Integer.parseInt(DictUtils.getDictValue(CategoryMap.map.get(allName),allName)));
                    info.setTertiaryCategory(0);
                    info.setAmount(Double.parseDouble(entry.getValue().toString()));
                }
                //建立对象  一对一、一对二    其他 的情况
                else if ((first.contains("一")||first.contains("二")||first.contains("三")||first.contains("四"))&&info.getIncomeDataId()==null&&second!=null){
                    info.setIncomeDataId(id);

                    int firstCategory= Integer.parseInt(DictUtils.getDictValue("first_category_type",first));
                    //获取第一级对应的名称以便下面找第二级对应的字典的数
                    String type= CategoryMap.map.get(first);

                    int secondaryCategory=Integer.parseInt(DictUtils.getDictValue(type,second));
                    //获取第二级对应的名称以便下面找第三级对应的字典的数
                    String thirdType=CategoryMap.map.get(second);

                    int tertiaryCategory;
                    //重点：通过name寻找第三级，第三级字典正好只有一个，则不论为金额还是产量，
                    // 对应的都是其name，当第二个数据录入，结果依旧保存在这一户对应的一级二级三级关系中
                    tertiaryCategory=Integer.parseInt(DictUtils.getDictValue(thirdType,name));
            //将其写入对应的对象当中
                    info.setFirstCategory(firstCategory);
                    info.setSecondaryCategory(secondaryCategory);

                    info.setTertiaryCategory(tertiaryCategory);
            //到此，那一列数据对应的一级二级三级字典已经与收入表id对应
                    String sQuantity1 = map.getOrDefault(name + "(产销)", "");
                    String sQuantity2=map.getOrDefault(name+"（产销）","");

                    double quantity=0.0;
                    if (!sQuantity1.equals(""))
                        quantity=Integer.parseInt(sQuantity1);
                    if (!sQuantity2.equals(""))
                        quantity=Integer.parseInt(sQuantity2);

                    //如果三级菜单没有产销量则设为null
                    if (Objects.equals(name, allName))
                        info.setQuantity(null);
                    //如果三级菜单有产销量但无数据则为0.0
                    else
                        info.setQuantity(quantity);



                    String sAmount1 = map.getOrDefault(name + "(金额)", "");
                    String sAmount2=map.getOrDefault(name+"（金额）","");
                    String sAmount3=map.getOrDefault(name,"");


                    double amount=0.0;
                    if (!sAmount1.equals(""))
                        amount=Double.parseDouble(sAmount1);
                    if (!sAmount2.equals(""))
                        amount=Double.parseDouble(sAmount2);
                    if (!sAmount3.equals(""))
                        amount=Double.parseDouble(sAmount3);
                    //金额所有三级菜单都有，则如果无数据则为0.0
                    info.setAmount(amount);
                }

                if (info.getFirstCategory() != null&&info.getSecondaryCategory()!=null&&info.getTertiaryCategory()!=null){
                    //通过一级与二级三级收入确定农户收入详情表的id
                    //表明如果之前已经录入了，则在相同的关系下，新建的这个对象，把这个对象覆盖原来的对象
                    Integer tmpId=baseFamilyInfoManagementMapper.selectDetailDBID(info.getIncomeDataId(),info.getFirstCategory(),info.getSecondaryCategory(),info.getTertiaryCategory());
                    if (tmpId!=null)
                        info.setId(tmpId);


                    if (info.getFirstCategory()==1)
                        produceAmount+=info.getAmount();
                    else if (info.getFirstCategory() == 2)
                        propertyAmount+=info.getAmount();
                    else if(info.getFirstCategory()==3)
                        salaryAmount+=info.getAmount();
                    else if(info.getFirstCategory()==4)
                        transferAmount+=info.getAmount();

                  //将产销量与金额为0.0或者没有的数据都变成null好判断
                    Double tmpAmount= info.getAmount()==0.0?null:info.getAmount();
                    info.setAmount(tmpAmount);

                    //新建一个集合用来存放有数据的关系表
                    //有循环，表明有用的数据已经都存入到里面了
                    detailDBList.add(info);
                    //可以优化：只需判断金额是否为null即可，金额为null，则产销量一定为null
                    // 去除没有金额与产销量的数据，节省数据库空间
                    if (info.getAmount()==null&&info.getQuantity()==null)
                        detailDBList.remove(info);
                }
                set.add(name);
            }

            //开始处理收入数据表，即一级收入表单
            //说明有这一户，但是没有这个年份
            if (functionMapper.selectOverviewDB(fid, Integer.parseInt(year))==null) {
                OverviewDB overviewDB = new OverviewDB();
                overviewDB.setId(id);
                //从户主表里面查找对应的户编号
                //生产经营性支出在三级表里有记载
                //有就转化为填入，无就写入0.00
                overviewDB.setFid(fid);
                if (map.getOrDefault("生产经营性支出", "").equals(""))
                    overviewDB.setExpense(0.00);
                else
                    overviewDB.setExpense(Double.parseDouble(map.getOrDefault("生产经营性支出", "")));
                //它的作用是通过指定日期格式来将日期类型的数据转化为指定格式的字符串类型数据。
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                Date date = new Date();
                overviewDB.setOpTime(sdf.format(date));
                //管理员账号
                User currentUser = ShiroUtils.getSysUser();
                // 获取当前的用户名称
                overviewDB.setUserId(currentUser.getUserId());
                //exel获取的年份
                overviewDB.setReportYear(Integer.parseInt(year));
                overviewDB.setOpIncome(produceAmount);
                overviewDB.setPropertyIncome(propertyAmount);
                overviewDB.setSalaryIncome(salaryAmount);
                overviewDB.setTransferIncome(transferAmount);
                //重复设置，无用
                double expense = 0.0;
                if (map.containsKey("生产经营性支出") && map.get("生产经营性支出") != null)
                    expense = Double.parseDouble(map.get("生产经营性支出"));
                overviewDB.setExpense(expense);
                //新建的默认不封停
                overviewDB.setState(0);
                //将一级收入的四大收入相加的总计
                overviewDB.setSumIncome(produceAmount + propertyAmount + salaryAmount + transferAmount);
                //直接从exel上获得即可，或者查询也行
                int num = HuZhu.getNum();
                //收入减支出除以人口的人均纯收入
                overviewDB.setAvgIncome((produceAmount + propertyAmount + salaryAmount + transferAmount - expense) / num);
                //插入此户信息，因为没有这一户对应的年份
                saveOverviewDB(overviewDB);
                //没有这一户对应的年份，则新生成了id数据关系表也全为新建，即也为插入操作
                saveDetailList(detailDBList);
            }
            //如果不为新建的话，也执行插入语句
            else{
                //如果id已经存在，则不更新关系更新产销量
                //如果不存在则插入
                saveDetailList(detailDBList);
                double expense = 0.0;
                if (map.containsKey("生产经营性支出") && map.get("生产经营性支出") != null)
                    //记录新导入表的支出
                    expense = Double.parseDouble(map.get("生产经营性支出"));
                //exel获得人口数
                int num = HuZhu.getNum();
                //已存有该户的信息
                OverviewDB overviewDB=functionMapper.selectOverviewDB(fid, Integer.parseInt(year));
                //执行更新操作
                updateIncomeData(overviewDB,expense,num);
            }
        }
    }
    public void updateIncomeData(OverviewDB overviewDB,Double expense,Integer num){

        double produceAmountA=0;
        double propertyAmountA=0;
        double salaryAmountA=0;
        double transferAmountA=0;

        //重新计算 overviewDB的合计值
        //计算第一级四大总收入，以便到处exel表与收入表使用
        //获得该户该年所有的金额的集合
        List<DetailDB> list=functionMapper.selectDetailDBList(overviewDB.getId());
        for (DetailDB info : list) {
            //可去除，已经去除金额为的数据了，不需要判断
            if (info.getAmount()==null)
                continue;
            if (info.getFirstCategory()==1)
                produceAmountA+=info.getAmount();
            else if (info.getFirstCategory() == 2)
                propertyAmountA+=info.getAmount();
            else if(info.getFirstCategory()==3)
                salaryAmountA+=info.getAmount();
            else if(info.getFirstCategory()==4)
                transferAmountA+=info.getAmount();
        }
        overviewDB.setExpense(expense);
        overviewDB.setOpIncome(produceAmountA);
        overviewDB.setPropertyIncome(propertyAmountA);
        overviewDB.setSalaryIncome(salaryAmountA);
        overviewDB.setTransferIncome(transferAmountA);
        overviewDB.setSumIncome(produceAmountA + propertyAmountA + salaryAmountA + transferAmountA);
        overviewDB.setAvgIncome((produceAmountA + propertyAmountA + salaryAmountA + transferAmountA - expense) / num);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = new Date();
        overviewDB.setOpTime(sdf.format(date));
        //更新收入详情表单
        updateOverviewDB(overviewDB);
    }




    public void saveOverviewDB(OverviewDB overviewDB){
        functionMapper.saveOverviewDB(overviewDB);
    }

    /**
     * @Description: 获取（ 前的数据项

     * @param s:字符串
     * @Author: 郑吉志
     * @return: 数据项，返回s说明数据项是一对一模式
    */
    public String prefixStr(String s){
        for (int i = 0; i < s.length(); i++) {
            char c=s.charAt(i);
            if (c=='('||c=='（')
                return s.substring(0,i);
        }
        return s;
    }
    @Override
    public void seal(String flag, String year) {
        boolean judge= flag.equals("true");//为封停时，此时judge为false，传到拦截器表示该数据封停，不能操作//解封时反之
        int yearInt=Integer.parseInt(year);
        Integer tmp= judge?0:1; //方便为states设置状态，封停为1，解封为0

        Integer state=selectStateByYear(Integer.parseInt(year));
        if (state==null)
            throw new DataException("没有该年数据");

        if (state==0&&state.equals(tmp))
            throw new DataException(year+"年数据已解封");
        else if (state==1&&state.equals(tmp))
            throw new DataException(year+"年数据已封停");
        sealByYear(tmp,Integer.parseInt(year));
        SealInterceptor.FLAG.put(yearInt,judge);
    }
    @Override
    public List<String> selectNumFarmer() {
        return functionMapper.selectNumFarmer();
    }

    @Override
    public List<DetailDB> selectDetailDBList(int id) {
        return functionMapper.selectDetailDBList(id);
    }

    /**
     * @description: 根据户编号和年份去`busi_income_data`表中查找此户对应年份的收入相关信息
     * @author chen0
     * @date 2023/6/7 12:13
     * @version 1.0
     */
    @Override
    public OverviewDB selectOverviewDB(String fid,int year) {
        return functionMapper.selectOverviewDB(fid,year);
    }

    @Override
    public BasicInfo selectBasicInfo(String fid) {
        return functionMapper.selectBasicInfo(fid);
    }

    @Override
    public List<String> selectFidList() {
        List<String> fidList=functionMapper.selectFidList();
        if (fidList==null||fidList.size()==0)
            throw new DataException("没有农户信息");
        return fidList;
    }

    @Override
    public String getFid(String name, int num, double area) {
        return functionMapper.getFid(name, num, area);
    }

    @Override
    public void saveDetail(DetailDB db) {
        functionMapper.saveDetail(db);
    }

    @Override
    public void saveDetailList(List<DetailDB> list) {
        functionMapper.saveDetailList(list);
    }

    @Override
    public List<Integer> selectYear(int year) {
        return functionMapper.selectYear(year);
    }

    @Override
    public String selectName(String name) {
        return functionMapper.selectName(name);
    }

    @Override
    public Integer getLastId() {
        return functionMapper.getLastId();
    }

    @Override
    public BaseFamilyInfo selectHuZhu(String fid) {
        return functionMapper.selectHuZhu(fid);
    }
}

